﻿using System.Threading;

namespace DMedia.Fetion.Framework.Core
{
	/// <summary>
	/// 节点数据结构
	/// </summary>
	/// <typeparam name="T"></typeparam>
	/// <remarks>
	/// fanweixiao 2009/10/14 在频繁程度超过一定频率之后可以应用预分配N个节点的方式来提高整体性能，未实现。
	/// </remarks>
	internal class Node<T>
	{
		public Node<T> Next;
		public T Item;
	}

	/// <summary>
	/// 线程安全的队列
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public class ThreadSafeQueue<T>
	{
		#region Fields

		Node<T> head;
		Node<T> tail;

		#endregion

		#region .ctor

		public ThreadSafeQueue()
		{
			//head = new Node<T>();
			//tail = head;
			Init();
		}

		#endregion

		#region Methods

		/// <summary>
		/// 添加到队列里
		/// </summary>
		/// <param name="item"></param>
		public void Enqueue(T item)
		{
			Node<T> oldTail = null;
			Node<T> oldTailNext;

			Node<T> newNode = new Node<T> { Item = item };

			bool newNodeWasAdded = false;
			while (!newNodeWasAdded)
			{
				oldTail = tail;
				oldTailNext = oldTail.Next;

				if (tail == oldTail)
				{
					if (oldTailNext == null)
						newNodeWasAdded = CasAlgo<Node<T>>(ref tail.Next, null, newNode);
					else
						CasAlgo<Node<T>>(ref tail, oldTail, oldTailNext);
				}
			}

			CasAlgo<Node<T>>(ref tail, oldTail, newNode);
		}

		/// <summary>
		/// 从队列里弹出一项
		/// </summary>
		/// <param name="item">弹出的项</param>
		/// <returns>弹出是否成功</returns>
		public bool Dequeue(out T item)
		{
			item = default(T);
			Node<T> oldHead;

			bool haveAdvancedHead = false;
			while (!haveAdvancedHead)
			{
				oldHead = head;
				Node<T> oldTail = tail;
				Node<T> oldHeadNext = oldHead.Next;

				if (oldHead == head)
				{
					if (oldHead == oldTail)
					{
						if (oldHeadNext == null)
						{
							return false;
						}
						CasAlgo<Node<T>>(ref tail, oldTail, oldHeadNext);
					}

					else
					{
						item = oldHeadNext.Item;
						haveAdvancedHead = CasAlgo<Node<T>>(ref head, oldHead, oldHeadNext);
					}
				}
			}
			return true;
		}

		/// <summary>
		/// 从队列里弹出一项
		/// </summary>
		/// <returns></returns>
		public T Dequeue()
		{
			T result;
			Dequeue(out result);
			return result;
		}

		/// <summary>
		/// 获取队列元素的个数
		/// </summary>
		public int GetCurrentCount()
		{
			int sum = 0;
			if (head == null)
				return 0;

			var tmpHead = head;
			while (tmpHead.Next != null)
			{
				sum++;
				tmpHead = tmpHead.Next;
			}

			return sum;
		}

		/// <summary>
		/// 清除当前队列
		/// </summary>
		public void Clear()
		{
			Init();
		}

		#endregion

		#region Help Methods

		/// <summary>
		/// Compare and Swap算法
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="location"></param>
		/// <param name="comparand"></param>
		/// <param name="newValue"></param>
		/// <returns></returns>
		private static bool CasAlgo<T>(ref T location, T comparand, T newValue) where T : class
		{
			return comparand == Interlocked.CompareExchange(ref location, newValue, comparand);
		}

		private void Init()
		{
			head = new Node<T>();
			tail = head;
		}

		#endregion
	}
}